package com.tony.jfp.core;

import com.tony.jfp.config.JFPProperties;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 正向代理转发服务管理
 */
@Component
@Slf4j
public class ProxyManagerVerticle extends AbstractVerticle implements InitializingBean {
    @Autowired
    protected Vertx vertx;
    /**
     * 配置信息
     */
    @Autowired
    protected JFPProperties properties;

    @Autowired
    protected SecurityService securityService;

    protected volatile String proxyDeploymentID = null;

    @Override
    public void afterPropertiesSet() throws Exception {
        vertx.deployVerticle(this);
    }

    @Override
    public void start() throws Exception {
        this.startServer().onSuccess(server -> {
            log.info("正向代理配置管理服务启动成功，监听端口：{}", properties.getPagePort());
            log.info("开始启动正向代理服务...");
            vertx.deployVerticle(new ForwardProxyVerticle(properties.getProxyPort(), vertx, securityService)).onSuccess(deploymentID -> {
                proxyDeploymentID = deploymentID;
                log.info("启动正向代理服务成功，deployId：{}！",deploymentID);
            }).onFailure(e -> {
                log.error("启动正向代理服务异常：{}", e.getMessage());
            });
        }).onFailure(ex -> {
            log.error("配置管理服务启动失败：{}", ex.getMessage());
        });
    }

    /**
     * 启动管理服务
     *
     * @return 启动future
     */
    private Future<HttpServer> startServer() {
        Router router = Router.router(vertx);
        Route route = properties.getPagePath() != null ? router.route(properties.getPagePath()) : router.route();
        route.blockingHandler(ctx -> {
            HttpServerRequest request = ctx.request();
            HttpServerResponse response = ctx.response();
            if (request.method() == HttpMethod.HEAD) {
                log.info("HEAD from remote：{}", request.remoteAddress().toString());
                response.setStatusCode(HttpResponseStatus.OK.code()).end();
            } else {
                log.info("remote：{}", request.remoteAddress().toString());
                String host = request.remoteAddress().host();
                String authorization = request.headers().get("authorization");
                //401 Unauthorized
                //www-authenticate: Basic realm="Restricted Area"
                //authorization:Basic bG9uZ3J1YW46TFJANjg4MDc4
                if (securityService.authorize(request.method().name(), host, authorization)) {
                    response.putHeader("content-type", "text/plain");
                    response.setStatusCode(HttpResponseStatus.OK.code());
                    response.end("Welcome to use jfp(Java Forward Proxy)! Your WAN IP is [" + host + "]!");
                } else {
                    response.headers().set("www-authenticate", securityService.getWWWAuthenticate(host));
                    response.setStatusCode(HttpResponseStatus.UNAUTHORIZED.code()).end();
                }
            }
        });
        return vertx.createHttpServer().requestHandler(router).listen(properties.getPagePort());
    }
}
